import React, {PureComponent, useEffect, useState, useRef} from 'react';
import {
  View,
  StyleSheet,
  Text,
  TextInput,
  Image,
  TouchableOpacity,
  Keyboard,
  Modal,
  DeviceEventEmitter,
  PanResponder,
  Linking,
  DeviceInfo,
} from 'react-native';
import I18n from 'react-native-i18n';
import {connect} from 'react-redux';
import BaseComponent from '../base/BaseComponent';
import {ImageButton, TextButton} from '../../components/Button';
import {NormalHeader} from '../../components/NavigationHeader';
import {showToast} from '../../components/Toast';
import {bindWallet} from '../../api/user';
import {
  userLogout,
  setCurrentChainId,
  updateUserInfo,
} from '../../redux/action';
import Clipboard from '@react-native-community/clipboard';
import WebView from 'react-native-webview';
import {
  SPA_urlChangeListener,
  JS_DESELECT_TEXT,
  JS_WEBVIEW_URL,
  JS_POST_MESSAGE_TO_PROVIDER,
} from '../../utils/browserScripts';
import EntryScriptWeb3 from '../../utils/EntryScriptWeb3';
import {Colors} from '../../styles/common';
import {useWalletConnect} from '@walletconnect/react-native-dapp';
import StorageManager, {
  BROWSER_HISTORY,
  METAMASK_ADDRESS,
  WEB_MENU_BOTTOM,
} from '../../storage';
// import {CachedImage} from 'react-native-img-cache';
import Device from '../../utils/device';

const qs = require('url');

const Web3 = require('web3');

function getChainRpc(chainId) {
  let rpcs = {
    1: 'https://mainnet.infura.io/v3/66fb1babc5664c7694d0e2d93cb1b038',
    3: 'https://ropsten.infura.io/v3/66fb1babc5664c7694d0e2d93cb1b038',
    4: 'https://rinkeby.infura.io/v3/66fb1babc5664c7694d0e2d93cb1b038',
    5: 'https://goerli.infura.io/v3/66fb1babc5664c7694d0e2d93cb1b038',
    42: 'https://kovan.infura.io/v3/66fb1babc5664c7694d0e2d93cb1b038',
    256: 'https://http-testnet.hecochain.com',
    97: 'https://data-seed-prebsc-1-s1.binance.org:8545/',
    56: 'https://bsc-dataseed1.binance.org/',
  };
  return rpcs[chainId];
}

export function WalletBrowser({
  url,
  event,
  web3Rpc,
  chainId,
  checkWalletConnect,
  registAddress,
}) {
  const connector = useWalletConnect();

  console.log('init connector', connector);

  if (chainId) {
    var rpc = getChainRpc(chainId) ? getChainRpc(chainId) : web3Rpc;
  } else {
    var rpc = getChainRpc(connector.chainId)
      ? getChainRpc(connector.chainId)
      : web3Rpc;
  }
  let web3 = new Web3(new Web3.providers.HttpProvider(rpc));

  const webview = useRef(null);

  let [webUrl, setWebUrl] = useState();

  let [userAgent, setUserAgent] = useState('123123');

  let [
    injectedJavaScriptBeforeContentLoaded,
    setInjectedJavaScriptBeforeContentLoaded,
  ] = useState('');

  let [progress, setProgress] = useState(0);

  let [marginBottom, setMarginBottom] = useState(100);

  let panResponder = PanResponder.create({
    onMoveShouldSetPanResponder: (evt, gestureState) => {
      //return true if user is swiping, return false if it's a single click
      return !(gestureState.dx === 0 && gestureState.dy === 0);
    },
    onPanResponderGrant: (evt, gestureState) => {},
    onPanResponderMove: (evt, gestureState) => {
      // console.log(
      //   `gestureState.dx : ${gestureState.dx}   gestureState.dy : ${gestureState.dy}`,
      // );
      setMarginBottom(marginBottom - gestureState.dy);
    },
    onPanResponderRelease: (evt, gestureState) => {
      console.log('marginBottom' + marginBottom);
      StorageManager.save(WEB_MENU_BOTTOM, marginBottom + '');
    },
    onPanResponderTerminate: (evt, gestureState) => {},
  });

  useEffect(() => {
    console.log('-----------初始化browser');

    StorageManager.load(WEB_MENU_BOTTOM).then((res) => {
      if (res) {
        console.log('bootom' + res);
        setMarginBottom(parseFloat(res));
      }
    });

    Device.getUserAgent().then((res) => {
      console.log('获取到用户agent为' + res);
      setUserAgent(res + ' sign_browser');
      console.log('执行js注入');

      getEntryScriptWeb3();
    });

    // let _webview = webview;

    let resumeGame = DeviceEventEmitter.addListener('enterGame', () => {
      console.log('重新进入游戏，发出通知');
      webview.current &&
        webview.current.postMessage(
          JSON.stringify({
            payload: {
              status: 'foreground',
            },
            type: 'GAME_STATUS',
          }),
        );
    });

    let linkingListen = Linking.addEventListener('url', (event) => {
      // console.log(webview.current);
      handleOpenURL(event.url);
    });

    let minisizeGameListen = DeviceEventEmitter.addListener(
      'notifyMiniSizeGame',
      minisizeGame,
    );

    return () => {
      console.log('浏览器页面销毁，移除通知');
      resumeGame && resumeGame.remove();
      linkingListen && linkingListen.remove();
      minisizeGameListen && minisizeGameListen.remove();
    };
  }, []);

  handleOpenURL = async (url) => {
    url = decodeURIComponent(url);

    console.log('---跳转的url为' + url);
    try {
      let paramsPart = url.split('?')[1];
      let params = paramsPart.split('&') || [];
      let param = {};
      params.map((item) => {
        let key = item.split('=')[0];
        let value = item.split('=')[1];
        param[key] = value;
      });
      console.log(param);
      if (param.chain) {
        let res = JSON.parse(param.chain);
        console.log('切换的chain信息为', JSON.stringify(res, null, 2));
        console.log(connector.chainId);

        //更新chainId
        event &&
          event({
            type: 'chainId',
            data: parseInt(res.chainId, 16),
          });

        //更新web3
        web3 = new Web3(
          new Web3.providers.HttpProvider(
            getChainRpc(parseInt(res.chainId, 16)),
          ),
        );

        if (connector.connected) {
          console.log('切换chainId');
          connector.updateSession({
            chainId: parseInt(res.chainId, 16),
            networkId: parseInt(res.chainId, 16),
            accounts: connector.accounts,
          });
        }

        console.log('切换后');
        console.log(connector.chainId);
      }
    } catch (err) {
      //   this._showAlert(err);
    }
  };

  const connectWallet = async () => {
    return new Promise(async (resolve, reject) => {
      if (connector.connected) {
        console.log('====================================');
        console.log('已连接');
        console.log(connector.accounts);
        console.log('====================================');
        resolve(connector.accounts[0]);
        return;
      }
      try {
        console.log('开始连接');
        let res = await connector.connect();
        console.log('连接成功' + JSON.stringify(res));
        // this.onConnect(payload);
        const {peerId, chainId, accounts} = res;
        if (!peerId) {
          showToast('Connection Failed');
          reject('peerId is not exist!');
        }
        // setLocalAddress(accounts[0]);
        showToast('Connection successed');
        registAddress && registAddress(accounts[0]);
        resolve(accounts[0]);
      } catch (err) {
        console.log('connect钱包出现错误' + err);
        showToast('Connection Failed');
        reject(err);
      }
    });
  };

  const onMessage = async ({nativeEvent}) => {
    if (
      JSON.stringify(nativeEvent).indexOf('net_version') == -1 &&
      JSON.stringify(nativeEvent).indexOf('eth_chainId') == -1
    ) {
      console.log('onMessage');
      console.log(nativeEvent);
    }

    let data = nativeEvent.data;
    try {
      data = typeof data === 'string' ? JSON.parse(data) : data;

      if (
        JSON.stringify(data).indexOf('net_version') == -1 &&
        JSON.stringify(data).indexOf('eth_chainId') == -1
      ) {
        console.log('请求的数据为');
        console.log(data);
      }

      if (!data || (!data.type && !data.name)) {
        console.log('数据不合法');
        return;
      }

      if (data.type == 'OPEN_URL_BROWSER') {
        Linking.openURL(data?.payload?.url);
      } else if (data?.payload?.method) {
        if (
          JSON.stringify(data).indexOf('net_version') == -1 &&
          JSON.stringify(data).indexOf('eth_chainId') == -1
        ) {
          console.log('====================================');
          console.log(checkWalletConnect());
          if (checkWalletConnect() === false) {
            console.log('未连接钱包，直接连接');
            await connectWallet();
          } else {
            console.log('钱包已连接');
          }
        }

        let result = await rpcMethods(data.payload.method, data.payload.params);
        if (
          JSON.stringify(data).indexOf('net_version') == -1 &&
          JSON.stringify(data).indexOf('eth_chainId') == -1
        ) {
          console.log('响应的数据' + result);
        }

        if (result) {
          let body = {
            ...data,
            payload: {
              ...data.payload,
              response: {
                result,
              },
            },
            type: 'INPAGE_RESPONSE',
          };
          // console.log(body);
          webview.current && webview.current.postMessage(JSON.stringify(body));
          // console.log('返回js消息');
        }
      }

      // console.log('处理请求结束');
    } catch (err) {
      console.log('解析或者接收到非正确格式的数据');
      console.log(err);

      let body = {
        ...data,
        payload: {
          ...data.payload,
          error: err,
          response: undefined,
        },
        type: 'INPAGE_RESPONSE',
      };
      console.log(body);
      webview.current && webview.current.postMessage(JSON.stringify(body));
    }
  };

  const rpcMethods = async (method, params) => {
    const web3Methods = {
      eth_getTransactionByHash: web3.eth.getTransaction,
      eth_getTransactionByBlockHashAndIndex: async () => {},
      eth_getTransactionByBlockNumberAndIndex: async () => {},
      eth_chainId: () => {
        // console.log('当前chainId为' + Web3.utils.toHex(connector.chainId));
        if (chainId) {
          return chainId;
        }
        return Web3.utils.toHex(connector.chainId);
      },
      net_version: () => {
        if (chainId) {
          return chainId;
        }
        // console.log('当前net为' + Web3.utils.toHex(connector.chainId));
        return Web3.utils.toHex(connector.chainId);
      },
      eth_requestAccounts: () => {
        return connector.accounts;
      },
      eth_accounts: () => {
        return connector.accounts;
      },
      eth_coinbase: async () => {},
      web3_clientVersion: async () => {},
      eth_blockNumber: web3.eth.getBlockNumber,
      eth_getBlockByNumber: web3.eth.getBlock,
      eth_gasPrice: web3.eth.getGasPrice,
      eth_getBalance: web3.eth.getBalance,
      eth_getTransactionReceipt: web3.eth.getTransactionReceipt,
    };

    const connectorMethods = {
      eth_requestAccounts: async () => {
        // return connector.accounts;
        let res = await StorageManager.load(METAMASK_ADDRESS);
        return JSON.parse(res).address;
      },
      eth_accounts: async () => {
        // return connector.accounts;
        let res = await StorageManager.load(METAMASK_ADDRESS);
        return JSON.parse(res).address;
      },
      eth_sendTransaction: async () => {
        console.log('====================================');
        console.log(connector.connected);
        console.log('====================================');
        if (params[0].value === undefined) {
          console.log('交易缺少value，添加');
          params[0].value = '0x0';
        }

        if (params[0].gasLimit === undefined) {
          console.log('交易缺少gasLimit，添加');
          params[0].gasLimit = web3.utils.toHex(110000);
        }

        if (params[0].gasPrice === undefined) {
          console.log('交易缺少gasPrice，获取并添加');
          // let thisWeb3 = new Web3(new Web3.providers.HttpProvider(web3Rpc));
          params[0].gasPrice = await web3.eth.getGasPrice();
        }
        // let args = Array.prototype.slice.call(arguments);
        console.log('发送待签名数据' + JSON.stringify(params, null, 2));
        return connector.sendTransaction.apply(connector, params);
      },
      eth_signTransaction: () => {
        let args = Array.prototype.slice.call(arguments);
        return connector.signTransaction.apply(null, args);
      },
      eth_sign: () => {
        let args = Array.prototype.slice.call(arguments);
        return connector.signTypedData.apply(null, args);
      },
      personal_sign: () => {
        let args = Array.prototype.slice.call(arguments);
        return connector.signPersonalMessage.apply(null, args);
      },
      eth_signTypedData: () => {
        let args = Array.prototype.slice.call(arguments);
        return connector.signTypedData.apply(null, args);
      },
      wallet_addEthereumChain: () => {
        let args = Array.prototype.slice.call(arguments);
        return connector.updateChain.apply(null, args);
      },
      wallet_switchEthereumChain: () => {},
      wallet_scanQRCode: () => {},
    };

    if (params && params.length != 0) {
      console.log('请求附带的参数', params);
    }

    if (web3Methods[method]) {
      return await web3Methods[method].apply(null, params);
    } else if (connectorMethods[method]) {
      return await connectorMethods[method].apply(null, params);
    } else {
      let funcParams = method.split('_');

      console.log(funcParams);
      console.log('请求的方法为', funcParams.join('.'));

      if (funcParams.length == 2) {
        return await web3[funcParams[0]][funcParams[1]].apply(null, params);
      } else if (funcParams.length == 3) {
        return await web3[funcParams[0]][funcParams[1]][funcParams[2]].apply(
          null,
          params,
        );
      } else {
        return null;
      }
    }
  };

  const getEntryScriptWeb3 = async () => {
    const entryScriptWeb3 = await EntryScriptWeb3.get();

    // console.log('entryScriptWeb3', entryScriptWeb3);
    setInjectedJavaScriptBeforeContentLoaded(
      entryScriptWeb3 + SPA_urlChangeListener,
    );
    setWebUrl(url);
    console.log('注入结束,刷新页面');
  };

  const onShouldStartLoadWithRequest = (data) => {
    console.log('加载请求' + JSON.stringify(data));
    return true;
  };

  const onLoadProgress = (syntheticEvent) => {
    console.log('进度回调' + syntheticEvent.nativeEvent.progress);
    setProgress(syntheticEvent.nativeEvent.progress);
  };

  const onLoadStart = () => {
    console.log('加载开始');
  };

  const onLoadEnd = () => {
    console.log('加载结束');
  };

  const onNavigationStateChange = (navState) => {
    console.log('加载的网页标题', navState.title);
    console.log(navState);

    // if (navState.url != url) {
    //   return;
    // }

    let urlObj = new qs.parse(navState.url);
    console.log(urlObj.hostname);

    event &&
      event({
        type: 'title',
        data: {
          title: navState.title ? navState.title : urlObj.hostname,
          url: navState.url,
          icon: 'https://' + urlObj.hostname + '/favicon.ico',
        },
      });
  };

  const minisizeGame = (hiddenGame) => {
    // console.log('最小化游戏', webview.current);

    webview.current &&
      webview.current.postMessage(
        JSON.stringify({
          payload: {
            status: 'background',
          },
          type: 'GAME_STATUS',
        }),
      );

    if (hiddenGame) {
      DeviceEventEmitter.emit('webview', {type: 'minsize'});
    }
  };

  return (
    <View style={{flex: 1, position: 'relative'}}>
      {url && webUrl ? (
        <WebView
          decelerationRate={'normal'}
          ref={webview}
          renderError={() => {
            <Text>error</Text>;
          }}
          source={{uri: webUrl, headers: {'Cache-Control': 'no-cache'}}}
          injectedJavaScriptBeforeContentLoaded={
            injectedJavaScriptBeforeContentLoaded
          }
          style={{flex: 1}}
          // onError={this.onError}
          onLoadStart={onLoadStart}
          // onLoad={this.onLoad}
          onLoadEnd={onLoadEnd}
          onNavigationStateChange={onNavigationStateChange}
          onLoadProgress={onLoadProgress}
          onMessage={onMessage}
          onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
          userAgent={userAgent}
          sendCookies
          javascriptEnabled
        />
      ) : null}
      <View
        {...panResponder.panHandlers}
        style={{
          position: 'absolute',
          left: 0,
          bottom: marginBottom,
          width: 40,
          height: 40,
          borderTopRightRadius: 20,
          borderBottomRightRadius: 20,
          backgroundColor: 'rgba(255,255,255,0.85)',
          alignItems: 'center',
          flexDirection: 'row',
          paddingLeft: 8,
        }}>
        <ImageButton
          buttonStyle={{
            with: 21,
            height: 21,
          }}
          source={require('../../assets/browser/game_home.png')}
          onPress={() => {
            console.log('游戏最小化，发出通知');
            minisizeGame(true);
          }}></ImageButton>
        {/* <View
          style={{
            marginLeft: 10,
            marginRight: 10,
            height: 20,
            width: 2,
            borderRadius: 1,
            backgroundColor: Colors.fontGrayColor_a0,
          }}></View>
        <ImageButton
          onStartShouldSetResponderCapture={true}
          onMoveShouldSetResponderCapture={false}
          buttonStyle={{
            with: 21,
            height: 21,
          }}
          onPress={() => {
            DeviceEventEmitter.emit('webview', {type: 'close'});
          }}
          source={require('../../assets/browser/game_close.png')}></ImageButton> */}
      </View>
      {progress !== 1 ? (
        <View
          style={{
            position: 'absolute',
            width: '100%',
            height: 2,
            left: 0,
            bottom: 0,
            backgroundColor: Colors.bgGrayColor_e5,
          }}>
          <View
            style={{
              width: `${progress * 100}%`,
              height: 2,
              backgroundColor: Colors.fontPurpleColorLight,
            }}></View>
        </View>
      ) : null}
    </View>
  );
}

//#FFCB26
class Browser extends BaseComponent {
  constructor(props) {
    super(props);

    this.state = {
      title: '',
      canGoBack: false,
      canGoForward: true,
    };

    console.log('需要加载url为' + this.props.url);
  }

  // componentWillReceiveProps(nextProps) {
  //   console.log('接收props', nextProps.url);
  //   this.setState({
  //     url: nextProps.url,
  //   });
  // }

  registAddress = async (address) => {
    console.log('注册钱包地址');
    console.log(address);
    console.log(this.props.userInfo.token);

    bindWallet({
      address,
      userToken: this.props.userInfo.token,
    }).then((res) => {
      console.log('绑定钱包地址成功');
    });

    // let result = await registAddress({address});
    StorageManager.save(
      METAMASK_ADDRESS,
      JSON.stringify({
        address: address,
        // token: result.data.token,
        hiddenAlert: false,
      }),
    );
    this.props.updateUserInfo({
      ...this.props.userInfo,
      metamaskAddress: address,
      // metamaskToken: result.data.token,
    });
  };

  tapWebFunc = (index) => {
    if (index == 2) {
      this.setState({
        url: 'https://signin.art',
      });
    }
  };

  event = ({type, data}) => {
    console.log('收到浏览器事件' + type + data);
    if (type == 'title') {
      this.setState({
        title: data.title,
      });

      Image.getSize(
        data.icon,
        (width, height) => {
          console.log('获取图片宽高', width + '___' + height);
          data.iconRatio = width == 0 ? 1 : height / width;
          if (width == 0) {
            data.icon = 'https://signin.art/resource/web.png';
            data.iconRatio = 1;
          } else {
            data.iconRatio = height / width;
          }

          //保存浏览器信息
          StorageManager.load(BROWSER_HISTORY).then((res) => {
            let historys = [data];
            if (res) {
              let arrs = JSON.parse(res).filter((item) => item.url != data.url);
              historys = historys.concat(arrs);
            }
            StorageManager.save(BROWSER_HISTORY, JSON.stringify(historys));
            DeviceEventEmitter.emit('historyRefresh');
          });
        },
        () => {
          data.icon = 'https://signin.art/resource/web.png';
          data.iconRatio = 1;

          //保存浏览器信息
          StorageManager.load(BROWSER_HISTORY).then((res) => {
            let historys = [data];
            if (res) {
              let arrs = JSON.parse(res).filter((item) => item.url != data.url);
              historys = historys.concat(arrs);
            }
            StorageManager.save(BROWSER_HISTORY, JSON.stringify(historys));
            DeviceEventEmitter.emit('historyRefresh');
          });
        },
      );
    } else if (type == 'chainId') {
      this.props.setCurrentChainId(data);
    }
  };

  checkWalletConnect = () => {
    console.log('====================================');
    console.log(this.props.userInfo);
    console.log('====================================');
    if (!this.props.userInfo.metamaskAddress) {
      // this._showAlert({
      //   content: 'Please connect to wallet',
      //   okTitle: 'Next',
      //   alertOkPress: () => {
      //     this.props.navigation.navigate('BrowserNewWallet');
      //   },
      // });
      return false;
    }

    return true;
  };

  renderComponent = () => {
    return (
      <View style={{flex: 1, backgroundColor: '#fff'}}>
        {/* <NormalHeader
          navigation={this.props.navigation}
          bgStyle={{
            backgroundColor: '#000',
          }}
          text={this.state.title}
          left={{
            icon: require('../../assets/common/common_back_white.png'),
            onPress: () => {
              Keyboard.dismiss();
              this.props.navigation.goBack();
            },
          }}
        /> */}
        <View style={{flex: 1}}>
          <WalletBrowser
            event={this.event}
            url={this.props.url}
            web3Rpc={this.props.chainConfig.url}
            chainId={this.props.currentChainId}
            checkWalletConnect={this.checkWalletConnect}
            registAddress={this.registAddress}
          />
        </View>
      </View>
    );
  };
}

const mapStateToProps = (state) => ({
  userInfo: state.User.userInfo,
  // widgetLayout: state.Layout.widgetLayout,
  chainConfig: state.Chain.config,
  currentChainId: state.Chain.currentChainId,
  // url: state.Game.url,
});

const mapDispatchToProps = (dispatch) => ({
  userLogout: (item) => dispatch(userLogout()),
  updateUserInfo: (item) => dispatch(updateUserInfo(item)),
  setCurrentChainId: (item) => dispatch(setCurrentChainId(item)),
});

export default connect(mapStateToProps, mapDispatchToProps)(Browser);
